/*
 * @FileName: bsp_pwm.c
 * @Author: GreyQiu qiushaogui@aikosolar.com
 * @Date: 2023-07-12 16:05:59
 * @LastEditors: GreyQiu qiushaogui@aikosolar.com
 * @LastEditTime: 2023-09-05 14:47:24
 * @Description: 
 * 
 * Copyright (c) 2023, All Rights Reserved. 
 */

#include "bsp_pwm.h"
#include "bsp.h"


/**
 * @description: PWM引脚配置
 * @return 无
 */
static void epwm1_gpio_config(void)
{
    // GPIO0 设置为EPWM1_A
    GPIO_setPinConfig(GPIO_0_EPWM1_A);
    GPIO_setPadConfig(0, GPIO_PIN_TYPE_STD);
    GPIO_setQualificationMode(0, GPIO_QUAL_SYNC);

    // GPIO1 设置为EPWM1_B
    GPIO_setPinConfig(GPIO_1_EPWM1_B);
    GPIO_setPadConfig(1, GPIO_PIN_TYPE_STD);
    GPIO_setQualificationMode(1, GPIO_QUAL_SYNC);
}

static void epwm2_gpio_config(void)
{
    // GPIO2 设置为EPWM2_A
    GPIO_setPinConfig(GPIO_41_EPWM2_A);
    GPIO_setPadConfig(41, GPIO_PIN_TYPE_STD);
    GPIO_setQualificationMode(41, GPIO_QUAL_SYNC);

    // GPIO3 设置为EPWM2_B
    GPIO_setPinConfig(GPIO_40_EPWM2_B);
    GPIO_setPadConfig(40, GPIO_PIN_TYPE_STD);
    GPIO_setQualificationMode(40, GPIO_QUAL_SYNC);
}

/**
 * @description: 将目标PWM配置为带死区的互补模式
 * @return 无
 */
static void pwm_basic_config(uint32_t base, uint16_t periodCount, uint16_t cntStart,uint16_t dtCount)
{
    /* 配置TB */
    EPWM_setClockPrescaler(base, EPWM_CLOCK_DIVIDER_1, EPWM_HSCLOCK_DIVIDER_1); // 时钟分频
    EPWM_setTimeBasePeriod(base, periodCount);      // 时基周期
    EPWM_setTimeBaseCounter(base, cntStart);               // 计数器初始值
    EPWM_setTimeBaseCounterMode(base, EPWM_COUNTER_MODE_UP_DOWN); // 计数器模式->中心对称模式

    /* 配置CMPA 用于占空比 */
    EPWM_setCounterCompareValue(base, EPWM_COUNTER_COMPARE_A, PWM_DUTY_CNT_START);
    EPWM_setCounterCompareShadowLoadMode(base, EPWM_COUNTER_COMPARE_A, EPWM_COMP_LOAD_ON_SYNC_CNTR_ZERO_PERIOD); // 比较值更新时刻

    /* 配置CMPD 可能会用于ADC触发事件生成 */
    EPWM_setCounterCompareValue(base, EPWM_COUNTER_COMPARE_D, periodCount / 2); // 周期的一半
    EPWM_setCounterCompareShadowLoadMode(base, EPWM_COUNTER_COMPARE_D, EPWM_COMP_LOAD_ON_SYNC_CNTR_ZERO_PERIOD); // 比较值更新时刻

    /* 配置AQ 各比较事件发生时 OUTPUTA 的动作*/
    EPWM_setActionQualifierAction(base, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
    EPWM_setActionQualifierAction(base, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_PERIOD);
    EPWM_setActionQualifierAction(base, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_LOW,       EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
    EPWM_setActionQualifierAction(base, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_HIGH,      EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA);
    EPWM_setActionQualifierAction(base, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPB);
    EPWM_setActionQualifierAction(base, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPB);

    /* 配置DB 生成带死区的PWM互补输出对 */
    EPWM_setDeadBandCounterClock(base, EPWM_DB_COUNTER_CLOCK_FULL_CYCLE); // 死时钟为PWM时钟的两倍
    EPWM_setRisingEdgeDeadBandDelayInput(base, EPWM_DB_INPUT_EPWMA); // 上管引脚参考信号为EPWMA
    EPWM_setFallingEdgeDeadBandDelayInput(base, EPWM_DB_INPUT_EPWMA); // 下管引脚参考信号为EPWMA
    EPWM_setDeadBandDelayPolarity(base, EPWM_DB_RED, EPWM_DB_POLARITY_ACTIVE_HIGH); // 上管跟随参考信号
    EPWM_setDeadBandDelayPolarity(base, EPWM_DB_FED, EPWM_DB_POLARITY_ACTIVE_LOW); // 下管与参考信号反相
    EPWM_setDeadBandDelayMode(base, EPWM_DB_RED, true); // 使能上管死区
    EPWM_setDeadBandDelayMode(base, EPWM_DB_FED, true); // 使能下管死区
    EPWM_setRisingEdgeDelayCount(base, dtCount);  // 上管死区时间
    EPWM_setFallingEdgeDelayCount(base, dtCount); // 下管死区时间
    // 禁止使用影子寄存器更新死区
    EPWM_setDeadBandControlShadowLoadMode(base, EPWM_DB_LOAD_ON_CNTR_ZERO);
    EPWM_setRisingEdgeDelayCountShadowLoadMode(base, EPWM_RED_LOAD_ON_CNTR_ZERO);
    EPWM_setFallingEdgeDelayCountShadowLoadMode(base, EPWM_FED_LOAD_ON_CNTR_ZERO);
    EPWM_disableRisingEdgeDelayCountShadowLoadMode(base);
    EPWM_disableFallingEdgeDelayCountShadowLoadMode(base);
    EPWM_disableDeadBandControlShadowLoadMode(base);
}

/**
 * @description: PWM的同步配置-主
 * @return 无
 */
static void pwm_sync_master_config(uint32_t base, uint16_t source)
{
    EPWM_enableSyncOutPulseSource(base, source); // 使能对外同步信号->计数器
    EPWM_disablePhaseShiftLoad(base); // 禁止相移
    EPWM_setPhaseShift(base, 0);
}

/**
 * @description: PWM的同步配置-从
 * @return 无
 */
static void pwm_sync_slave_config(uint32_t base,
                                  EPWM_SyncInPulseSource syncInSource,
                                  EPWM_SyncCountMode mode,
                                  uint16_t phaseCount)
{
    EPWM_setSyncInPulseSource(base, syncInSource);     // 设置同步信号
    EPWM_setCountModeAfterSync(base, mode); // 同步后计数器方向
    EPWM_setPhaseShift(base, phaseCount); // 设置相移值
    EPWM_enablePhaseShiftLoad(base);    // 使能相移（同步后将phaseCount搬运至计数器）
}

/**
 * @description: PWM的比较器cbc保护配置
 * @return 无
 */
static void pwm_tz_cbc_config(uint32_t base,
                              EPWM_DigitalCompareTripInput tripSource)
{
//    /* 配置TZ 选择比较器作为触发源源 */
////    XBAR_setInputPin(INPUTXBAR_BASE, XBAR_INPUT1, 17);
//    XBAR_setEPWMMuxConfig(XBAR_TRIP4, XBAR_EPWM_MUX00_CMPSS1_CTRIPH); // TRIP4的MUX00选择比较器1输出
//    XBAR_enableEPWMMux(XBAR_TRIP4, XBAR_MUX00); // 使能MUX00 与 EPWM.TRIP4的连接
    // DCXH选择与tripSource连接
//    EPWM_selectDigitalCompareTripInput(base, tripSource, EPWM_DC_TYPE_DCAH); // DCA控制EPWM_A
//    EPWM_selectDigitalCompareTripInput(base, tripSource, EPWM_DC_TYPE_DCBH); // DCB控制EPWM_B
    // 当DCXH置高时，触发DCAEVT2事件
//    EPWM_setTripZoneDigitalCompareEventCondition(base, EPWM_TZ_DC_OUTPUT_A2, EPWM_TZ_EVENT_DCXH_HIGH);
//    EPWM_setTripZoneDigitalCompareEventCondition(base, EPWM_TZ_DC_OUTPUT_B2, EPWM_TZ_EVENT_DCXH_HIGH);
    // DCXEVT2不滤波
    EPWM_setDigitalCompareEventSource(base, EPWM_DC_MODULE_A, EPWM_DC_EVENT_2, EPWM_DC_EVENT_SOURCE_ORIG_SIGNAL);
    EPWM_setDigitalCompareEventSource(base, EPWM_DC_MODULE_B, EPWM_DC_EVENT_2, EPWM_DC_EVENT_SOURCE_ORIG_SIGNAL);
    // CBC设置
    EPWM_setDigitalCompareCBCLatchMode(base, EPWM_DC_MODULE_A, EPWM_DC_EVENT_2, EPWM_DC_CBC_LATCH_ENABLED);
    EPWM_setDigitalCompareCBCLatchMode(base, EPWM_DC_MODULE_B, EPWM_DC_EVENT_2, EPWM_DC_CBC_LATCH_ENABLED);
    EPWM_selectDigitalCompareCBCLatchClearEvent(base, EPWM_DC_MODULE_A, EPWM_DC_EVENT_2, EPWM_DC_CBC_LATCH_CLR_CNTR_ZERO);
    EPWM_selectDigitalCompareCBCLatchClearEvent(base, EPWM_DC_MODULE_B, EPWM_DC_EVENT_2, EPWM_DC_CBC_LATCH_CLR_CNTR_ZERO);
    /* 配置TZ 故障事件发生时PWM的保护动作 */
    EPWM_setTripZoneAction(base, EPWM_TZ_ACTION_EVENT_DCAEVT2, EPWM_TZ_ACTION_LOW); // 触发DCAEVT2事件时,EPWM_A 置低
    EPWM_setTripZoneAction(base, EPWM_TZ_ACTION_EVENT_DCBEVT2, EPWM_TZ_ACTION_LOW); // 触发DCBEVT2事件时,EPWM_B 置高
}

/**
 * @description: PWM的比较器one-shot保护配置
 * @return 无
 */
static void pwm_tz_ost_config(uint32_t base,
                              EPWM_DigitalCompareTripInput tripSource)
{
//    /* 配置TZ 选择比较器作为触发源源 */
////    XBAR_setInputPin(INPUTXBAR_BASE, XBAR_INPUT1, 17);
//    XBAR_setEPWMMuxConfig(XBAR_TRIP4, XBAR_EPWM_MUX00_CMPSS1_CTRIPH); // TRIP4的MUX00选择比较器1输出
//    XBAR_enableEPWMMux(XBAR_TRIP4, XBAR_MUX00); // 使能MUX00 与 EPWM.TRIP4的连接
    // DCXH选择与TRIPIN4连接
    EPWM_selectDigitalCompareTripInput(base, tripSource, EPWM_DC_TYPE_DCAH); // DCA控制EPWM_A
    EPWM_selectDigitalCompareTripInput(base, tripSource, EPWM_DC_TYPE_DCBH); // DCB控制EPWM_B
    // 当DCXH置高时，触发DCAEVT1事件
    EPWM_setTripZoneDigitalCompareEventCondition(base, EPWM_TZ_DC_OUTPUT_A1, EPWM_TZ_EVENT_DCXH_HIGH);
    EPWM_setTripZoneDigitalCompareEventCondition(base, EPWM_TZ_DC_OUTPUT_B1, EPWM_TZ_EVENT_DCXH_HIGH);
    // DCXEVT2不滤波
    EPWM_setDigitalCompareEventSource(base, EPWM_DC_MODULE_A, EPWM_DC_EVENT_1, EPWM_DC_EVENT_SOURCE_ORIG_SIGNAL);
    EPWM_setDigitalCompareEventSource(base, EPWM_DC_MODULE_B, EPWM_DC_EVENT_1, EPWM_DC_EVENT_SOURCE_ORIG_SIGNAL);
    // CBC设置
    EPWM_setDigitalCompareCBCLatchMode(base, EPWM_DC_MODULE_A, EPWM_DC_EVENT_1, EPWM_DC_CBC_LATCH_DISABLED);
    EPWM_setDigitalCompareCBCLatchMode(base, EPWM_DC_MODULE_B, EPWM_DC_EVENT_1, EPWM_DC_CBC_LATCH_DISABLED);
//    EPWM_selectDigitalCompareCBCLatchClearEvent(EPWM1_BASE, EPWM_DC_MODULE_A, EPWM_DC_EVENT_2, EPWM_DC_CBC_LATCH_CLR_CNTR_ZERO);
//    EPWM_selectDigitalCompareCBCLatchClearEvent(EPWM1_BASE, EPWM_DC_MODULE_B, EPWM_DC_EVENT_2, EPWM_DC_CBC_LATCH_CLR_CNTR_ZERO);
    /* 配置TZ 故障事件发生时PWM的保护动作 */
    EPWM_setTripZoneAction(base, EPWM_TZ_ACTION_EVENT_TZA, EPWM_TZ_ACTION_LOW); // 触发DCAEVT2事件时,EPWM_A 置低
    EPWM_setTripZoneAction(base, EPWM_TZ_ACTION_EVENT_TZB, EPWM_TZ_ACTION_LOW); // 触发DCBEVT2事件时,EPWM_B 置高
//    EPWM_enableTripZoneSignals(base, EPWM_TZ_SIGNAL_DCAEVT1);
//    EPWM_enableTripZoneSignals(base, EPWM_TZ_SIGNAL_DCBEVT1);
}

void pwm_adc_trig(uint32_t base,
                  EPWM_ADCStartOfConversionType adcSOCType,
                  EPWM_ADCStartOfConversionSource socSource,
                  uint16_t preScaleCount,
                  uint16_t eventCount)
{
    /* 配置ET 对外触发信号 用于触发ADC */
    EPWM_disableADCTrigger(base, adcSOCType);
    EPWM_setADCTriggerSource(base, adcSOCType, socSource);
    EPWM_setADCTriggerEventPrescale(base, adcSOCType, preScaleCount); // 触发分频

    // 设置ADC触发事件计数初始值
    EPWM_enableADCTriggerEventCountInit(base, adcSOCType);
    EPWM_setADCTriggerEventCountInitValue(base, adcSOCType, eventCount);
    EPWM_forceADCTriggerEventCountInit(base, adcSOCType);
    EPWM_disableADCTriggerEventCountInit(base, adcSOCType);

    EPWM_enableADCTrigger(base, adcSOCType);
}

/**
 * @description: pwm初始化
 * @return 无
 */
void bsp_pwm_init(void)
{
    SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);
    epwm1_gpio_config();
    epwm2_gpio_config();

    // 首先配置好TZ和DC，并软件触发关闭PWM的事件，确保配置PWM过程中引脚不发波
    // 发生FAULT时，包括软件触发的FUALT ，上下管均关闭。
    EPWM_setTripZoneAction(EPWM1_BASE, EPWM_TZ_ACTION_EVENT_TZA, EPWM_TZ_ACTION_LOW);
    EPWM_setTripZoneAction(EPWM1_BASE, EPWM_TZ_ACTION_EVENT_TZB, EPWM_TZ_ACTION_LOW);
    // 软件触发DCAEV1用于关闭同步整流
    EPWM_setTripZoneAction(EPWM1_BASE, EPWM_TZ_ACTION_EVENT_DCBEVT1, EPWM_TZ_ACTION_LOW); // 发生DCBEVT1事， EPWM1_B置低
    EPWM_setDigitalCompareEventSyncMode(EPWM1_BASE, EPWM_DC_MODULE_B, EPWM_DC_EVENT_1, EPWM_DC_EVENT_INPUT_SYNCED);
    EPWM_selectDigitalCompareCBCLatchClearEvent(EPWM1_BASE, EPWM_DC_MODULE_B, EPWM_DC_EVENT_1, EPWM_DC_CBC_LATCH_CLR_DISABLE); // 不清除DCAEV1
    EPWM_setDigitalCompareCBCLatchMode(EPWM1_BASE, EPWM_DC_MODULE_B, EPWM_DC_EVENT_1, EPWM_DC_CBC_LATCH_ENABLED); // 软件只会触发一个脉冲，需要锁存才能维持DCAEV1事件有效
    EPWM_forceTripZoneEvent(EPWM1_BASE, EPWM_TZ_FORCE_EVENT_DCBEVT1); // 触发DCAEV1
    EPWM_forceTripZoneEvent(EPWM1_BASE, EPWM_TZ_FORCE_EVENT_OST); // 触发OST
    // pwm2 控制PV2
    pwm_sync_master_config(EPWM1_BASE, EPWM_SYNC_OUT_PULSE_ON_CNTR_ZERO); // 配置PWM作为主，并选择对外触发信号
    pwm_adc_trig(EPWM1_BASE, EPWM_SOC_A, EPWM_SOC_TBCTR_ZERO, 2, 0); // 计数器=0触发一次事件，每2次事件触发一次ADC
    pwm_adc_trig(EPWM1_BASE, EPWM_SOC_B, EPWM_SOC_TBCTR_PERIOD, 2, 0); // 计数器=PRD触发产生一次事件，每2次事件触发一次ADC
    pwm_basic_config(EPWM1_BASE, PWM_PERIOD_CNT, 0, DEAD_TIME_H);
//    EPWM_setDeadBandOutputSwapMode(EPWM1_BASE, EPWM_DB_OUTPUT_A, true);
//    EPWM_setDeadBandOutputSwapMode(EPWM1_BASE, EPWM_DB_OUTPUT_B, true);

    // 发生FAULT时，包括软件触发的FUALT ，上下管均关闭。
    EPWM_setTripZoneAction(EPWM2_BASE, EPWM_TZ_ACTION_EVENT_TZA, EPWM_TZ_ACTION_LOW);
    EPWM_setTripZoneAction(EPWM2_BASE, EPWM_TZ_ACTION_EVENT_TZB, EPWM_TZ_ACTION_LOW);
    // 软件触发DCAEV1用于关闭同步整流
    EPWM_setTripZoneAction(EPWM2_BASE, EPWM_TZ_ACTION_EVENT_DCBEVT1, EPWM_TZ_ACTION_LOW);
    EPWM_setDigitalCompareEventSyncMode(EPWM2_BASE, EPWM_DC_MODULE_B, EPWM_DC_EVENT_1, EPWM_DC_EVENT_INPUT_SYNCED);
    EPWM_selectDigitalCompareCBCLatchClearEvent(EPWM2_BASE, EPWM_DC_MODULE_B, EPWM_DC_EVENT_1, EPWM_DC_CBC_LATCH_CLR_DISABLE); // 不清除DCAEV1
    EPWM_setDigitalCompareCBCLatchMode(EPWM2_BASE, EPWM_DC_MODULE_B, EPWM_DC_EVENT_1, EPWM_DC_CBC_LATCH_ENABLED); // 软件只会触发一个脉冲，需要锁存才能维持DCAEV1事件有效
    EPWM_forceTripZoneEvent(EPWM2_BASE, EPWM_TZ_FORCE_EVENT_DCBEVT1); // 触发DCAEV1
    EPWM_forceTripZoneEvent(EPWM2_BASE, EPWM_TZ_FORCE_EVENT_OST); // 触发OST
    // pwm4 控制PV2
    pwm_sync_slave_config(EPWM2_BASE, EPWM_SYNC_IN_PULSE_SRC_SYNCOUT_EPWM1,
                          EPWM_COUNT_MODE_DOWN_AFTER_SYNC, PWM_PERIOD_CNT); // 相对与EPWM1滞后180°
    pwm_adc_trig(EPWM2_BASE, EPWM_SOC_B, EPWM_SOC_TBCTR_ZERO, 2, 0); // 计数器=0 或 PRD时产生一次事件，每1次事件触发一次ADC
    pwm_adc_trig(EPWM2_BASE, EPWM_SOC_A, EPWM_SOC_TBCTR_PERIOD, 2, 1); // 计数器=0 或 PRD时产生一次事件，每1次事件触发一次ADC
    pwm_basic_config(EPWM2_BASE, PWM_PERIOD_CNT, PWM_PERIOD_CNT / 2, DEAD_TIME_H);
//    EPWM_setDeadBandOutputSwapMode(EPWM2_BASE, EPWM_DB_OUTPUT_A, false);
//    EPWM_setDeadBandOutputSwapMode(EPWM2_BASE, EPWM_DB_OUTPUT_B, false);

    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);
}

bool bsp_pwm_is_break(uint32_t base)
{
    return EPWM_getOneShotTripZoneFlagStatus(base);
}

void bsp_pwm_break_clear(uint32_t base)
{
    EPWM_clearTripZoneFlag(base, EPWM_TZ_FLAG_OST);
}
